#!/usr/bin/python
#
# Copyright (c) 2008, Mathias Weber
# Copyright (c) 2008, Thomas Stauffer
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
#   list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
#   this list of conditions and the following disclaimer in the documentation
#   and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# $Id: example-level.py 82 2008-10-12 22:28:21Z tymayos $

"""
Textures are from

http://developer.nvidia.com/object/IO_TTVol_01.html
"""

import sys
import random

import direct.directbase.DirectStart

base.setBackgroundColor(0.0, 0.0, 0.2)
base.disableMouse()
base.camLens.setNearFar(1.0, 100.0)
base.camLens.setFov(45.0)

camera.setPos(0.0, 0.0, 50.0)
camera.setHpr(0.0, -90.0, 0.0)

world = None

def load():
    """
    Create a random world. Panda3D has a cache for models internally. If you
    load the same model again and again, memory is only wasted once. The bad
    thing for this example is: to do a stress test to Panda3D we need to create
    tons of different models (or maybe is just that I am unable to find a clone
    method).
    """

    global world

    if world == None:
        print "Load"

        # Create a root node. Every model we load should be reparented to world.
        world = render.attachNewNode("World")

        # Create the map.
        size = 50
        models = [ "example-level-meadow", "example-level-river" ]
        for y in range(size):
            for x in range(size):
                model = loader.loadModel(random.choice(models)).getChild(0)
                model.reparentTo(world)
                model.setPos(x, y, 0.0)

def unload():
    """
    Removes the world from the scene graph. If models are not reused in the next
    level then loader.unloadModel would be appropriate. A better solution may
    load the next level and only unloads the models not used in the new level.
    But this far away from perfect solution. Remember all this A+++ games where
    you enter a house, get your quest, leave the house and have to wait a long
    time, till the scene you were one minute ago is reloaded?
    """

    global world

    if world != None:
        print "Unload"

        # The method removeNode removes the node from the scene graph and memory.
        world.removeNode()
        world = None

def flatten():
    """
    Optimize the geometry. In this example we flatten the whole world node. That
    can be time consuming and is maybe not the best idea anyway because the
    whole operation can reduce the scene graph to only one node. One node means
    only one cull check and only one draw call but maybe it is so large that the
    graphic card needs to much time to render the node. Like ever you should
    optimally utilize the CPU and the GPU.
    """

    global world

    if world != None:
        print "Flatten"
        world.flattenStrong()

base.accept("escape", sys.exit)
base.accept("a", render.analyze)
base.accept("o", base.oobe)
base.accept("l", render.ls)
base.accept("f", flatten)
base.accept("1", load)
base.accept("2", unload)

run()
